#pragma once
#include "socket_server.h"
#include "Epoll.h"
#include <unistd.h>
#include <fcntl.h>

#define default_port 8888

using namespace Network_module;
using namespace Epoll_module;

class Epoll_server
{
    const static int g_maxevents = 37;

public:
    Epoll_server(uint16_t port = default_port)
        : _tcp_socket(make_unique<Tcp>(port)), _port(port), _epoller(make_unique<Epoll>())
    {
    }

    void Init()
    {
        // 1.网络(创建tcp listen套接字)
        _tcp_socket->Creat_socket();
        _tcp_socket->Bind();
        _tcp_socket->Listen();

        // 2.多路转接-epoll(创建epoll模型)
        _epoller->Epoll_Init();

        // 3.listen_sockfd添加到epoll(红黑树)中
        _epoller->Epoll_addevent(_tcp_socket->Get_sockfd(), EPOLLIN);
    }

    void Run()
    {
        while (true)
        {
            int n = _epoller->Epoll_wait(_revents, g_maxevents, -1); // 5000->等待5s
            // Epoll_wait将已经等待成功的事件放到_revents(就绪队列)里
            switch (n)
            {
            case 0:
                cout << "no file descriptor became ready during the requested timeout..." << endl;
                break;
            case -1:
                std::cerr << "epoll_wait error... " << strerror(errno) << std::endl;
                break;
            default:
                // cout << "event preparation..." << endl;
                Handler_event(n);
                break;
            }
        }
    }

    ~Epoll_server()
    {
    }

private:
    unique_ptr<Tcp> _tcp_socket;
    unique_ptr<Epoll> _epoller;
    uint16_t _port;
    epoll_event _revents[g_maxevents];

private:

    void Handler_event(int n)
    {

        for (int i = 0; i < n; i++)
        {
            int sockfd = _revents[i].data.fd;
            uint32_t event = _revents[i].events;

            if (event & EPOLLIN) // 读事件就绪
            {
                if (sockfd == _tcp_socket->Get_sockfd()) // 1.新连接
                {
                    int newsockfd = _tcp_socket->Accept();
                    _epoller->Epoll_addevent(newsockfd, EPOLLIN); // 将新的连接添加到epoll(红黑树)
                }
                else // 2.数据到来
                {
                    // 读取数据// tcp数据流，数据不一定会一次全部读完
                    char buffer[1024];

                    int n = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        n -= strlen("\r\n"); // telnet发送数据，末尾自带换行符\r\n
                        buffer[n] = 0;
                        cout << "sockfd = " << sockfd << " say: " << buffer << endl;
                    }
                    else
                    {
                        if (n == 0)
                            cout << "客户端关闭连接..." << endl;
                        else
                            cerr << "数据读取失败..." << endl;

                        // 取消epoll关心,关闭文件
                        _epoller->Del_event(sockfd);
                        close(sockfd);
                    }

                    // 返回数据
                    string ret = (string) "hello->" + buffer + "\r\n";
                    send(sockfd, ret.c_str(), ret.size(), 0);
                }
            }
        }
    }
};